package com.ldgk.pim.client.view.gwt;

import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import com.google.gwt.maps.client.MapWidget;
import com.google.gwt.maps.client.event.MapMoveEndHandler;
import com.google.gwt.maps.client.geom.LatLng;
import com.google.gwt.search.client.LocalResult;
import com.ldgk.pim.client.presenter.MapPresenter;
import com.ldgk.pim.client.presenter.MarkerPresenter;
import com.ldgk.pim.client.presenter.Presenter;
import com.ldgk.pim.client.util.GeoHash;
import com.ldgk.pim.client.util.Util;
import com.ldgk.pim.client.view.MapView;
import com.ldgk.pim.client.view.components.PowerMarker;
import com.ldgk.pim.data.Place;

/**
 * Map View GWT Implementation
 */
public class MapViewImpl implements MapView{
	/** Map widget */
	private MapWidget map = new MapWidget();
	/** 
	 * Map presenter, responsible for handling some ui
	 * events and executing business logic (or some of it)
	 */
	private MapPresenter presenter;
	/** Marker presenter used to create and manipulate map markers */
	private MarkerPresenter markerPresenter;
	/** Local results currently showing on map */
	private HashMap<String,PowerMarker> showingResults = new HashMap<String,PowerMarker>();
	/** Distribution places currently showing on map */
	private HashMap<String,PowerMarker> distributionPlaces = new HashMap<String,PowerMarker>();
	
	/**
	 * Default constructor, instantiates the necessary presenters
	 */
	public MapViewImpl(){
		this.markerPresenter = new MarkerPresenter(new MarkerViewImpl(),this);
		Util.markerPresenter = this.markerPresenter;
		//Add the map move handler
		this.addMoveEndHandler();
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void setPresenter(Presenter presenter){
		this.presenter = (MapPresenter)presenter;
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void setMapCenter(LatLng center){
		this.map.setCenter(center);
	}

	/**
	 * {@inheritDoc}
	 */
	public LatLng getMapCenter(){
		return this.map.getCenter();
	}

	/**
	 * {@inheritDoc}
	 */
	public void addLocalResult(LocalResult result){
		String geohash = GeoHash.fromLatLng(result.getLat(),result.getLng()).toBase32();
		if(!distributionPlaces.containsKey(geohash)){
			PowerMarker marker = markerPresenter.createMarker(result);
			showingResults.put(geohash,marker);
			this.map.addOverlay(marker);
		}
	}
	
	/**
	 * {@inheritDoc}
	 */
	public void addDistributionPlace(Place place){
		String geohash = place.getGeoHash();
		//If database place is showing as a google local result, remove the local result
		if( showingResults.containsKey(geohash)){
			this.map.removeOverlay(showingResults.get(geohash));
			showingResults.remove(geohash);
		}
		//Put the marker
		PowerMarker marker = markerPresenter.createMarker(place);
		distributionPlaces.put(geohash,marker);		
		this.map.addOverlay(marker);
	}

	/**
	 * {@inheritDoc}
	 */
	public void clearLocalResults(){
		Collection<PowerMarker> collection = showingResults.values();
		Iterator<PowerMarker> it = collection.iterator();
		while(it.hasNext()){
			this.map.removeOverlay(it.next());
		}
		this.showingResults.clear();
	}

	/**
	 * {@inheritDoc}
	 */
	public void clearDistributionPlaces(){
		Collection<PowerMarker> collection = distributionPlaces.values();
		Iterator<PowerMarker> it = collection.iterator();
		while(it.hasNext()){
			this.map.removeOverlay(it.next());
		}
		this.distributionPlaces.clear();
	}

	/**
	 * {@inheritDoc}
	 */
	public void clearAll(){
		clearLocalResults();
		clearDistributionPlaces();
	}
	
	/**
	 * {@inheritDoc}
	 */
	public MapWidget getMapWidget(){
		return this.map;
	}
	
	private void addMoveEndHandler(){
		this.map.addMapMoveEndHandler(new MapMoveEndHandler(){
			public void onMoveEnd(MapMoveEndHandler.MapMoveEndEvent event){
				if( map.getZoomLevel() > 13 )
					presenter.findPlacesInsideLatLng(map.getBounds().getNorthEast(),map.getBounds().getSouthWest());
				else
					presenter.clearMap();
			}
		});
	}
}
